﻿// Inner Kit 通用工具库
// SpritePack（精灵打包类）
//
// Copyright (c) 2024 by 尔西大帝. All rights reserved.
//
// 这个类用于将一系列的小图片打包成一个大图片包。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2024-12-22

#pragma once

#include <base_struct.h>
#include <image.h>
#include <iostream>
#include <kits.h>
#include <EASTL/vector.h>
#include <xml_reader.h>

namespace ikit {

constexpr int SPRITE_PACK_BLOCK = 32;
constexpr std::uint32_t SPRITE_PACK_COLOR_KEY = DXRGB(255, 0, 255);

// 类的声明，因为需要父类，所以先声明
class SpriteImage;
typedef SpriteImage* LPSpriteImage;
class SpriteElement;
typedef SpriteElement* LPSpriteElement;
class SpritePack;
typedef SpritePack* LPSpritePack;
class SpriteGrid;
typedef SpriteGrid* LPSpriteGrid;

class SpriteImage {
public:
  int index;
  LPSpriteElement parent;
  int width;      // 图片宽
  int height;     // 图片高
  Rect rect;      // 这个Sprite在大图中的位置（用于直接Blt）
  RectF rectf;     // 这个Sprite在大图中的位置（用于贴图）
  std::string filename; // 文件名
  ImageData png;  // 此文件载入的项目
  int rotation;   // 旋转的角度，以度数（360）为单位
  bool flipX;     // 是否翻转X
  bool flipY;     // 是否翻转Y

  SpriteImage(LPSpriteElement parent, int index, const XmlNode& node);
  ~SpriteImage();

  void Load(void);
  // 标志这个Sprite是否有效，出现图片丢失的情况就是无效
  bool IsValid(void) const;
  void Fill(std::uint32_t* buffer, int lpitch, int x, int y);
  std::uint32_t PickPixel(int x, int y) const;
  // 获得颜色的BUFFER（主要是32位可以用到这个）
  const unsigned char* GetBuffer() const;
  // 获取原始的图片信息
  int GetBitmapWidth(void) const;
  int GetBitmapHeight(void) const;

};

class SpriteElement {
public:
  LPSpritePack parent;
  int id; // 此项目的ID
  ikit::sstr name;
  LPSpriteImage* items;
  int column; // 每行的Sprite的数量（这个需要在XML中指定，如果为0，则以count为准）
  int row;    // 总共的行数（通过计算获得）
  int x;      // 在图像中的位置
  int y;      // 在图像中的位置
  int width;  // 整个SpriteGroup的宽
  int height; // 整个SpriteGroup的高
  int count;  // 数量
  float scale;    // 缩放
  int grid_width; // GRID的宽，是所有子元素Width的最大值。这个和column相乘，就得到整个图片的宽。
  int grid_height; // GRID的高，是所有子元素Height的最大值。这个和row相乘，就得到整个图片的高。

  SpriteElement(
      LPSpritePack parent, int id, const XmlNode& node);
  ~SpriteElement();

  void Add(LPSpriteImage e, int index);
  void Load(void);
  void Print(void);
  void Fill(std::uint32_t* buffer, int lpitch);
  // 返回第一个，这是最常用的
  LPSpriteImage First(void) const;

  LPSpriteImage Find(int index) const;

  
};

class SpritePack {

public:
  SpritePack(const XmlNode& node, int index);
  ~SpritePack();

  ikit::sstr name;
  int width;
  int height;
  eastl::vector<LPSpriteElement> items;
  bool alphaToColorKey;
  // 用于外部创建项目所需要的IMG结构
  ImageData img;
  // 用于贴图的计算
  float texture_size;

  void Build(float rate);

  // 填充进一个BUFFER，这个BUFFER的大小与本PACK的大小一样
  void Fill(std::uint32_t* buffer, int lpitch);
  // 查找一个Element
  LPSpriteImage Find(const char* name, int index = 0);
  LPSpriteElement FindElement(const char* name);
  LPSpriteElement FindElement(const ikit::sstr name);
  // 此Pack是否正常载入
  bool IsLoaded(void) const;

private:
  // 表示是否正常载入
  bool is_loaded;

  // 载入所有的图片信息
  void Load(void);
  // 将所有的图片信息打包成一个Surface
  void Pack(void);
};

class SpriteGrid {
private:
  void Fill(LPSpriteElement g, int x, int y);
  bool IsStackable(int x, int y, int gx, int gy);

public:
  char* grid;
  int grid_size;
  int x_far;
  int y_far;

  SpriteGrid(LPSpritePack pack, float rate);
  ~SpriteGrid();

  bool Stack(LPSpriteElement g);
  void Print();
};

using SpritePackPtr = std::unique_ptr<SpritePack>;

} // namespace ikit